package xyz.jcat.sco.admin.oauth2.server.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import xyz.jcat.sco.admin.oauth2.server.auth.CreateTokenService;
import xyz.jcat.sco.admin.oauth2.server.auth.UserAuthenticationProcessingFilter;
import xyz.jcat.sco.admin.oauth2.server.auth.UserAuthenticationProvider;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private ClientDetailsService clientDetailsService;
    @Autowired
    private AuthorizationServerTokenServices authorizationServerTokenServices;
    @Autowired
    private AuthenticationSuccessHandler authenticationSuccessHandler;
    @Autowired
    private AuthenticationFailureHandler authenticationFailureHandler;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UserDetailsService userDetailsService;

    private AuthenticationProvider userAuthenticationProvider() {
        return new UserAuthenticationProvider(this.userDetailsService, this.passwordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/oauth2/**")
                .permitAll()
                .and()
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and().csrf().disable();
        http.addFilterAfter(userAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
            .authenticationProvider(userAuthenticationProvider());
}

    private AbstractAuthenticationProcessingFilter userAuthenticationProcessingFilter() throws Exception {
        UserAuthenticationProcessingFilter userAuthenticationProcessingFilter = new UserAuthenticationProcessingFilter();
        userAuthenticationProcessingFilter.setAuthenticationManager(authenticationManager());
        userAuthenticationProcessingFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
        userAuthenticationProcessingFilter.setAuthenticationFailureHandler(authenticationFailureHandler);
        return userAuthenticationProcessingFilter;
    }

    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public CreateTokenService createTokenService() {
        return new CreateTokenService(
                clientDetailsService,
                new DefaultOAuth2RequestFactory(clientDetailsService),
                authorizationServerTokenServices,
                passwordEncoder);
    }

}
